(function (f) {
    if (typeof exports === "object" && typeof module !== "undefined") {
        module.exports = f()
    } else if (typeof define === "function" && define.amd) {
        define([], f)
    } else {
        var g; if (typeof window !== "undefined") {
            g = window
        } else if (typeof global !== "undefined") {
            g = global
        } else if (typeof self !== "undefined") {
            g = self
        } else {
            g = this
        } 
        window.poly2tri = g.poly2tri = f();
    }
})(function () {
    var define, module, exports; return (function e(t, n, r) {
        function s(o, u) {
            if (!n[o]) {
                if (!t[o]) {
                    var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f
                } var l = n[o] = {
                    exports: {

                    }
                }; t[o][0].call(l.exports, function (e) {
                    var n = t[o][1][e]; return s(n ? n : e)
                }, l, l.exports, e, t, n, r)
            } return n[o].exports
        } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++)s(r[o]); return s
    })({
        1: [function (require, module, exports) {

            module.exports = {
                "version": "1.5.0"
            }
        }, {

        }], 2: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            /* jshint maxcomplexity:11 */

            "use strict";


            /*
             * Note
             * ====
             * the structure of this JavaScript version of poly2tri intentionally follows
             * as closely as possible the structure of the reference C++ version, to make it
             * easier to keep the 2 versions in sync.
             */


            // -------------------------------------------------------------------------Node

            /**
             * Advancing front node
             * @constructor
             * @private
             * @struct
             * @param {!XY} p - Point
             * @param {Triangle=} t triangle (optional)
             */
            var Node = function (p, t) {
                /** @type {XY} */
                this.point = p;

                /** @type {Triangle|null} */
                this.triangle = t || null;

                /** @type {Node|null} */
                this.next = null;
                /** @type {Node|null} */
                this.prev = null;

                /** @type {number} */
                this.value = p.x;
            };

            // ---------------------------------------------------------------AdvancingFront
            /**
             * @constructor
             * @private
             * @struct
             * @param {Node} head
             * @param {Node} tail
             */
            var AdvancingFront = function (head, tail) {
                /** @type {Node} */
                this.head_ = head;
                /** @type {Node} */
                this.tail_ = tail;
                /** @type {Node} */
                this.search_node_ = head;
            };

            /** @return {Node} */
            AdvancingFront.prototype.head = function () {
                return this.head_;
            };

            /** @param {Node} node */
            AdvancingFront.prototype.setHead = function (node) {
                this.head_ = node;
            };

            /** @return {Node} */
            AdvancingFront.prototype.tail = function () {
                return this.tail_;
            };

            /** @param {Node} node */
            AdvancingFront.prototype.setTail = function (node) {
                this.tail_ = node;
            };

            /** @return {Node} */
            AdvancingFront.prototype.search = function () {
                return this.search_node_;
            };

            /** @param {Node} node */
            AdvancingFront.prototype.setSearch = function (node) {
                this.search_node_ = node;
            };

            /** @return {Node} */
            AdvancingFront.prototype.findSearchNode = function (/*x*/) {
                // TODO: implement BST index
                return this.search_node_;
            };

            /**
             * @param {number} x value
             * @return {Node}
             */
            AdvancingFront.prototype.locateNode = function (x) {
                var node = this.search_node_;

                /* jshint boss:true */
                if (x < node.value) {
                    while (node = node.prev) {
                        if (x >= node.value) {
                            this.search_node_ = node;
                            return node;
                        }
                    }
                } else {
                    while (node = node.next) {
                        if (x < node.value) {
                            this.search_node_ = node.prev;
                            return node.prev;
                        }
                    }
                }
                return null;
            };

            /**
             * @param {!XY} point - Point
             * @return {Node}
             */
            AdvancingFront.prototype.locatePoint = function (point) {
                var px = point.x;
                var node = this.findSearchNode(px);
                var nx = node.point.x;

                if (px === nx) {
                    // Here we are comparing point references, not values
                    if (point !== node.point) {
                        // We might have two nodes with same x value for a short time
                        if (point === node.prev.point) {
                            node = node.prev;
                        } else if (point === node.next.point) {
                            node = node.next;
                        } else {
                            throw new Error('poly2tri Invalid AdvancingFront.locatePoint() call');
                        }
                    }
                } else if (px < nx) {
                    /* jshint boss:true */
                    while (node = node.prev) {
                        if (point === node.point) {
                            break;
                        }
                    }
                } else {
                    while (node = node.next) {
                        if (point === node.point) {
                            break;
                        }
                    }
                }

                if (node) {
                    this.search_node_ = node;
                }
                return node;
            };


            // ----------------------------------------------------------------------Exports

            module.exports = AdvancingFront;
            module.exports.Node = Node;


        }, {}], 3: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            "use strict";

            /*
             * Function added in the JavaScript version (was not present in the c++ version)
             */

            /**
             * assert and throw an exception.
             *
             * @private
             * @param {boolean} condition   the condition which is asserted
             * @param {string} message      the message which is display is condition is falsy
             */
            function assert(condition, message) {
                if (!condition) {
                    throw new Error(message || "Assert Failed");
                }
            }
            module.exports = assert;



        }, {}], 4: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            "use strict";


            /*
             * Note
             * ====
             * the structure of this JavaScript version of poly2tri intentionally follows
             * as closely as possible the structure of the reference C++ version, to make it
             * easier to keep the 2 versions in sync.
             */

            var xy = require('./xy');

            // ------------------------------------------------------------------------Point
            /**
             * Construct a point
             * @example
             *      var point = new poly2tri.Point(150, 150);
             * @public
             * @constructor
             * @struct
             * @param {number=} x    coordinate (0 if undefined)
             * @param {number=} y    coordinate (0 if undefined)
             */
            var Point = function (x, y) {
                /**
                 * @type {number}
                 * @expose
                 */
                this.x = +x || 0;
                /**
                 * @type {number}
                 * @expose
                 */
                this.y = +y || 0;

                // All extra fields added to Point are prefixed with _p2t_
                // to avoid collisions if custom Point class is used.

                /**
                 * The edges this point constitutes an upper ending point
                 * @private
                 * @type {Array.<Edge>}
                 */
                this._p2t_edge_list = null;
            };

            /**
             * For pretty printing
             * @example
             *      "p=" + new poly2tri.Point(5,42)
             *      // → "p=(5;42)"
             * @returns {string} <code>"(x;y)"</code>
             */
            Point.prototype.toString = function () {
                return xy.toStringBase(this);
            };

            /**
             * JSON output, only coordinates
             * @example
             *      JSON.stringify(new poly2tri.Point(1,2))
             *      // → '{"x":1,"y":2}'
             */
            Point.prototype.toJSON = function () {
                return { x: this.x, y: this.y };
            };

            /**
             * Creates a copy of this Point object.
             * @return {Point} new cloned point
             */
            Point.prototype.clone = function () {
                return new Point(this.x, this.y);
            };

            /**
             * Set this Point instance to the origo. <code>(0; 0)</code>
             * @return {Point} this (for chaining)
             */
            Point.prototype.set_zero = function () {
                this.x = 0.0;
                this.y = 0.0;
                return this; // for chaining
            };

            /**
             * Set the coordinates of this instance.
             * @param {number} x   coordinate
             * @param {number} y   coordinate
             * @return {Point} this (for chaining)
             */
            Point.prototype.set = function (x, y) {
                this.x = +x || 0;
                this.y = +y || 0;
                return this; // for chaining
            };

            /**
             * Negate this Point instance. (component-wise)
             * @return {Point} this (for chaining)
             */
            Point.prototype.negate = function () {
                this.x = -this.x;
                this.y = -this.y;
                return this; // for chaining
            };

            /**
             * Add another Point object to this instance. (component-wise)
             * @param {!Point} n - Point object.
             * @return {Point} this (for chaining)
             */
            Point.prototype.add = function (n) {
                this.x += n.x;
                this.y += n.y;
                return this; // for chaining
            };

            /**
             * Subtract this Point instance with another point given. (component-wise)
             * @param {!Point} n - Point object.
             * @return {Point} this (for chaining)
             */
            Point.prototype.sub = function (n) {
                this.x -= n.x;
                this.y -= n.y;
                return this; // for chaining
            };

            /**
             * Multiply this Point instance by a scalar. (component-wise)
             * @param {number} s   scalar.
             * @return {Point} this (for chaining)
             */
            Point.prototype.mul = function (s) {
                this.x *= s;
                this.y *= s;
                return this; // for chaining
            };

            /**
             * Return the distance of this Point instance from the origo.
             * @return {number} distance
             */
            Point.prototype.length = function () {
                return Math.sqrt(this.x * this.x + this.y * this.y);
            };

            /**
             * Normalize this Point instance (as a vector).
             * @return {number} The original distance of this instance from the origo.
             */
            Point.prototype.normalize = function () {
                var len = this.length();
                this.x /= len;
                this.y /= len;
                return len;
            };

            /**
             * Test this Point object with another for equality.
             * @param {!XY} p - any "Point like" object with {x,y}
             * @return {boolean} <code>true</code> if same x and y coordinates, <code>false</code> otherwise.
             */
            Point.prototype.equals = function (p) {
                return this.x === p.x && this.y === p.y;
            };


            // -----------------------------------------------------Point ("static" methods)

            /**
             * Negate a point component-wise and return the result as a new Point object.
             * @param {!XY} p - any "Point like" object with {x,y}
             * @return {Point} the resulting Point object.
             */
            Point.negate = function (p) {
                return new Point(-p.x, -p.y);
            };

            /**
             * Add two points component-wise and return the result as a new Point object.
             * @param {!XY} a - any "Point like" object with {x,y}
             * @param {!XY} b - any "Point like" object with {x,y}
             * @return {Point} the resulting Point object.
             */
            Point.add = function (a, b) {
                return new Point(a.x + b.x, a.y + b.y);
            };

            /**
             * Subtract two points component-wise and return the result as a new Point object.
             * @param {!XY} a - any "Point like" object with {x,y}
             * @param {!XY} b - any "Point like" object with {x,y}
             * @return {Point} the resulting Point object.
             */
            Point.sub = function (a, b) {
                return new Point(a.x - b.x, a.y - b.y);
            };

            /**
             * Multiply a point by a scalar and return the result as a new Point object.
             * @param {number} s - the scalar
             * @param {!XY} p - any "Point like" object with {x,y}
             * @return {Point} the resulting Point object.
             */
            Point.mul = function (s, p) {
                return new Point(s * p.x, s * p.y);
            };

            /**
             * Perform the cross product on either two points (this produces a scalar)
             * or a point and a scalar (this produces a point).
             * This function requires two parameters, either may be a Point object or a
             * number.
             * @param  {XY|number} a - Point object or scalar.
             * @param  {XY|number} b - Point object or scalar.
             * @return {Point|number} a Point object or a number, depending on the parameters.
             */
            Point.cross = function (a, b) {
                if (typeof (a) === 'number') {
                    if (typeof (b) === 'number') {
                        return a * b;
                    } else {
                        return new Point(-a * b.y, a * b.x);
                    }
                } else {
                    if (typeof (b) === 'number') {
                        return new Point(b * a.y, -b * a.x);
                    } else {
                        return a.x * b.y - a.y * b.x;
                    }
                }
            };


            // -----------------------------------------------------------------"Point-Like"
            /*
             * The following functions operate on "Point" or any "Point like" object
             * with {x,y} (duck typing).
             */

            Point.toString = xy.toString;
            Point.compare = xy.compare;
            Point.cmp = xy.compare; // backward compatibility
            Point.equals = xy.equals;

            /**
             * Peform the dot product on two vectors.
             * @public
             * @param {!XY} a - any "Point like" object with {x,y}
             * @param {!XY} b - any "Point like" object with {x,y}
             * @return {number} The dot product
             */
            Point.dot = function (a, b) {
                return a.x * b.x + a.y * b.y;
            };


            // ---------------------------------------------------------Exports (public API)


            module.exports = Point;

        }, { "./xy": 11 }], 5: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            "use strict";

            /*
             * Class added in the JavaScript version (was not present in the c++ version)
             */

            var xy = require('./xy');

            /**
             * Custom exception class to indicate invalid Point values
             * @constructor
             * @public
             * @extends Error
             * @struct
             * @param {string=} message - error message
             * @param {Array.<XY>=} points - invalid points
             */
            var PointError = function (message, points) {
                this.name = "PointError";
                /**
                 * Invalid points
                 * @public
                 * @type {Array.<XY>}
                 */
                this.points = points = points || [];
                /**
                 * Error message
                 * @public
                 * @type {string}
                 */
                this.message = message || "Invalid Points!";
                for (var i = 0; i < points.length; i++) {
                    this.message += " " + xy.toString(points[i]);
                }
            };
            PointError.prototype = new Error();
            PointError.prototype.constructor = PointError;


            module.exports = PointError;

        }, { "./xy": 11 }], 6: [function (require, module, exports) {
            (function (global) {
                /*
                 * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
                 * http://code.google.com/p/poly2tri/
                 *
                 * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
                 * https://github.com/r3mi/poly2tri.js
                 *
                 * All rights reserved.
                 *
                 * Redistribution and use in source and binary forms, with or without modification,
                 * are permitted provided that the following conditions are met:
                 *
                 * * Redistributions of source code must retain the above copyright notice,
                 *   this list of conditions and the following disclaimer.
                 * * Redistributions in binary form must reproduce the above copyright notice,
                 *   this list of conditions and the following disclaimer in the documentation
                 *   and/or other materials provided with the distribution.
                 * * Neither the name of Poly2Tri nor the names of its contributors may be
                 *   used to endorse or promote products derived from this software without specific
                 *   prior written permission.
                 *
                 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
                 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
                 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                 */

                "use strict";

                /**
                 * Public API for poly2tri.js
                 * @module poly2tri
                 */


                /**
                 * If you are not using a module system (e.g. CommonJS, RequireJS), you can access this library
                 * as a global variable <code>poly2tri</code> i.e. <code>window.poly2tri</code> in a browser.
                 * @name poly2tri
                 * @global
                 * @public
                 * @type {module:poly2tri}
                 */
                var previousPoly2tri = global.poly2tri;
                /**
                 * For Browser + &lt;script&gt; :
                 * reverts the {@linkcode poly2tri} global object to its previous value,
                 * and returns a reference to the instance called.
                 *
                 * @example
                 *              var p = poly2tri.noConflict();
                 * @public
                 * @return {module:poly2tri} instance called
                 */
                // (this feature is not automatically provided by browserify).
                exports.noConflict = function () {
                    global.poly2tri = previousPoly2tri;
                    return exports;
                };

                /**
                 * poly2tri library version
                 * @public
                 * @const {string}
                 */
                exports.VERSION = require('../dist/version.json').version;

                /**
                 * Exports the {@linkcode PointError} class.
                 * @public
                 * @typedef {PointError} module:poly2tri.PointError
                 * @function
                 */
                exports.PointError = require('./pointerror');
                /**
                 * Exports the {@linkcode Point} class.
                 * @public
                 * @typedef {Point} module:poly2tri.Point
                 * @function
                 */
                exports.Point = require('./point');
                /**
                 * Exports the {@linkcode Triangle} class.
                 * @public
                 * @typedef {Triangle} module:poly2tri.Triangle
                 * @function
                 */
                exports.Triangle = require('./triangle');
                /**
                 * Exports the {@linkcode SweepContext} class.
                 * @public
                 * @typedef {SweepContext} module:poly2tri.SweepContext
                 * @function
                 */
                exports.SweepContext = require('./sweepcontext');


                // Backward compatibility
                var sweep = require('./sweep');
                /**
                 * @function
                 * @deprecated use {@linkcode SweepContext#triangulate} instead
                 */
                exports.triangulate = sweep.triangulate;
                /**
                 * @deprecated use {@linkcode SweepContext#triangulate} instead
                 * @property {function} Triangulate - use {@linkcode SweepContext#triangulate} instead
                 */
                exports.sweep = { Triangulate: sweep.triangulate };

            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, { "../dist/version.json": 1, "./point": 4, "./pointerror": 5, "./sweep": 7, "./sweepcontext": 8, "./triangle": 9 }], 7: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            /* jshint latedef:nofunc, maxcomplexity:9 */

            "use strict";

            /**
             * This 'Sweep' module is present in order to keep this JavaScript version
             * as close as possible to the reference C++ version, even though almost all
             * functions could be declared as methods on the {@linkcode module:sweepcontext~SweepContext} object.
             * @module
             * @private
             */

            /*
             * Note
             * ====
             * the structure of this JavaScript version of poly2tri intentionally follows
             * as closely as possible the structure of the reference C++ version, to make it
             * easier to keep the 2 versions in sync.
             */

            var assert = require('./assert');
            var PointError = require('./pointerror');
            var Triangle = require('./triangle');
            var Node = require('./advancingfront').Node;


            // ------------------------------------------------------------------------utils

            var utils = require('./utils');

            /** @const */
            var EPSILON = utils.EPSILON;

            /** @const */
            var Orientation = utils.Orientation;
            /** @const */
            var orient2d = utils.orient2d;
            /** @const */
            var inScanArea = utils.inScanArea;
            /** @const */
            var isAngleObtuse = utils.isAngleObtuse;


            // ------------------------------------------------------------------------Sweep

            /**
             * Triangulate the polygon with holes and Steiner points.
             * Do this AFTER you've added the polyline, holes, and Steiner points
             * @private
             * @param {!SweepContext} tcx - SweepContext object
             */
            function triangulate(tcx) {
                tcx.initTriangulation();
                tcx.createAdvancingFront();
                // Sweep points; build mesh
                sweepPoints(tcx);
                // Clean up
                finalizationPolygon(tcx);
            }

            /**
             * Start sweeping the Y-sorted point set from bottom to top
             * @param {!SweepContext} tcx - SweepContext object
             */
            function sweepPoints(tcx) {
                var i, len = tcx.pointCount();
                for (i = 1; i < len; ++i) {
                    var point = tcx.getPoint(i);
                    var node = pointEvent(tcx, point);
                    var edges = point._p2t_edge_list;
                    for (var j = 0; edges && j < edges.length; ++j) {
                        edgeEventByEdge(tcx, edges[j], node);
                    }
                }
            }

            /**
             * @param {!SweepContext} tcx - SweepContext object
             */
            function finalizationPolygon(tcx) {
                // Get an Internal triangle to start with
                var t = tcx.front().head().next.triangle;
                var p = tcx.front().head().next.point;
                while (!t.getConstrainedEdgeCW(p)) {
                    t = t.neighborCCW(p);
                }

                // Collect interior triangles constrained by edges
                tcx.meshClean(t);
            }

            /**
             * Find closes node to the left of the new point and
             * create a new triangle. If needed new holes and basins
             * will be filled to.
             * @param {!SweepContext} tcx - SweepContext object
             * @param {!XY} point   Point
             */
            function pointEvent(tcx, point) {
                var node = tcx.locateNode(point);
                var new_node = newFrontTriangle(tcx, point, node);

                // Only need to check +epsilon since point never have smaller
                // x value than node due to how we fetch nodes from the front
                if (point.x <= node.point.x + (EPSILON)) {
                    fill(tcx, node);
                }

                //tcx.AddNode(new_node);

                fillAdvancingFront(tcx, new_node);
                return new_node;
            }

            function edgeEventByEdge(tcx, edge, node) {
                tcx.edge_event.constrained_edge = edge;
                tcx.edge_event.right = (edge.p.x > edge.q.x);

                if (isEdgeSideOfTriangle(node.triangle, edge.p, edge.q)) {
                    return;
                }

                // For now we will do all needed filling
                // TODO: integrate with flip process might give some better performance
                //       but for now this avoid the issue with cases that needs both flips and fills
                fillEdgeEvent(tcx, edge, node);
                edgeEventByPoints(tcx, edge.p, edge.q, node.triangle, edge.q);
            }

            function edgeEventByPoints(tcx, ep, eq, triangle, point) {
                if (isEdgeSideOfTriangle(triangle, ep, eq)) {
                    return;
                }

                var p1 = triangle.pointCCW(point);
                var o1 = orient2d(eq, p1, ep);
                if (o1 === Orientation.COLLINEAR) {
                    // TODO integrate here changes from C++ version
                    // (C++ repo revision 09880a869095 dated March 8, 2011)
                    throw new PointError('poly2tri EdgeEvent: Collinear not supported!', [eq, p1, ep]);
                }

                var p2 = triangle.pointCW(point);
                var o2 = orient2d(eq, p2, ep);
                if (o2 === Orientation.COLLINEAR) {
                    // TODO integrate here changes from C++ version
                    // (C++ repo revision 09880a869095 dated March 8, 2011)
                    throw new PointError('poly2tri EdgeEvent: Collinear not supported!', [eq, p2, ep]);
                }

                if (o1 === o2) {
                    // Need to decide if we are rotating CW or CCW to get to a triangle
                    // that will cross edge
                    if (o1 === Orientation.CW) {
                        triangle = triangle.neighborCCW(point);
                    } else {
                        triangle = triangle.neighborCW(point);
                    }
                    edgeEventByPoints(tcx, ep, eq, triangle, point);
                } else {
                    // This triangle crosses constraint so lets flippin start!
                    flipEdgeEvent(tcx, ep, eq, triangle, point);
                }
            }

            function isEdgeSideOfTriangle(triangle, ep, eq) {
                var index = triangle.edgeIndex(ep, eq);
                if (index !== -1) {
                    triangle.markConstrainedEdgeByIndex(index);
                    var t = triangle.getNeighbor(index);
                    if (t) {
                        t.markConstrainedEdgeByPoints(ep, eq);
                    }
                    return true;
                }
                return false;
            }

            /**
             * Creates a new front triangle and legalize it
             * @param {!SweepContext} tcx - SweepContext object
             */
            function newFrontTriangle(tcx, point, node) {
                var triangle = new Triangle(point, node.point, node.next.point);

                triangle.markNeighbor(node.triangle);
                tcx.addToMap(triangle);

                var new_node = new Node(point);
                new_node.next = node.next;
                new_node.prev = node;
                node.next.prev = new_node;
                node.next = new_node;

                if (!legalize(tcx, triangle)) {
                    tcx.mapTriangleToNodes(triangle);
                }

                return new_node;
            }

            /**
             * Adds a triangle to the advancing front to fill a hole.
             * @param {!SweepContext} tcx - SweepContext object
             * @param node - middle node, that is the bottom of the hole
             */
            function fill(tcx, node) {
                var triangle = new Triangle(node.prev.point, node.point, node.next.point);

                // TODO: should copy the constrained_edge value from neighbor triangles
                //       for now constrained_edge values are copied during the legalize
                triangle.markNeighbor(node.prev.triangle);
                triangle.markNeighbor(node.triangle);

                tcx.addToMap(triangle);

                // Update the advancing front
                node.prev.next = node.next;
                node.next.prev = node.prev;


                // If it was legalized the triangle has already been mapped
                if (!legalize(tcx, triangle)) {
                    tcx.mapTriangleToNodes(triangle);
                }

                //tcx.removeNode(node);
            }

            /**
             * Fills holes in the Advancing Front
             * @param {!SweepContext} tcx - SweepContext object
             */
            function fillAdvancingFront(tcx, n) {
                // Fill right holes
                var node = n.next;
                while (node.next) {
                    // TODO integrate here changes from C++ version
                    // (C++ repo revision acf81f1f1764 dated April 7, 2012)
                    if (isAngleObtuse(node.point, node.next.point, node.prev.point)) {
                        break;
                    }
                    fill(tcx, node);
                    node = node.next;
                }

                // Fill left holes
                node = n.prev;
                while (node.prev) {
                    // TODO integrate here changes from C++ version
                    // (C++ repo revision acf81f1f1764 dated April 7, 2012)
                    if (isAngleObtuse(node.point, node.next.point, node.prev.point)) {
                        break;
                    }
                    fill(tcx, node);
                    node = node.prev;
                }

                // Fill right basins
                if (n.next && n.next.next) {
                    if (isBasinAngleRight(n)) {
                        fillBasin(tcx, n);
                    }
                }
            }

            /**
             * The basin angle is decided against the horizontal line [1,0].
             * @param {Node} node
             * @return {boolean} true if angle < 3*π/4
             */
            function isBasinAngleRight(node) {
                var ax = node.point.x - node.next.next.point.x;
                var ay = node.point.y - node.next.next.point.y;
                assert(ay >= 0, "unordered y");
                return (ax >= 0 || Math.abs(ax) < ay);
            }

            /**
             * Returns true if triangle was legalized
             * @param {!SweepContext} tcx - SweepContext object
             * @return {boolean}
             */
            function legalize(tcx, t) {
                // To legalize a triangle we start by finding if any of the three edges
                // violate the Delaunay condition
                for (var i = 0; i < 3; ++i) {
                    if (t.delaunay_edge[i]) {
                        continue;
                    }
                    var ot = t.getNeighbor(i);
                    if (ot) {
                        var p = t.getPoint(i);
                        var op = ot.oppositePoint(t, p);
                        var oi = ot.index(op);

                        // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization)
                        // then we should not try to legalize
                        if (ot.constrained_edge[oi] || ot.delaunay_edge[oi]) {
                            t.constrained_edge[i] = ot.constrained_edge[oi];
                            continue;
                        }

                        var inside = inCircle(p, t.pointCCW(p), t.pointCW(p), op);
                        if (inside) {
                            // Lets mark this shared edge as Delaunay
                            t.delaunay_edge[i] = true;
                            ot.delaunay_edge[oi] = true;

                            // Lets rotate shared edge one vertex CW to legalize it
                            rotateTrianglePair(t, p, ot, op);

                            // We now got one valid Delaunay Edge shared by two triangles
                            // This gives us 4 new edges to check for Delaunay

                            // Make sure that triangle to node mapping is done only one time for a specific triangle
                            var not_legalized = !legalize(tcx, t);
                            if (not_legalized) {
                                tcx.mapTriangleToNodes(t);
                            }

                            not_legalized = !legalize(tcx, ot);
                            if (not_legalized) {
                                tcx.mapTriangleToNodes(ot);
                            }
                            // Reset the Delaunay edges, since they only are valid Delaunay edges
                            // until we add a new triangle or point.
                            // XXX: need to think about this. Can these edges be tried after we
                            //      return to previous recursive level?
                            t.delaunay_edge[i] = false;
                            ot.delaunay_edge[oi] = false;

                            // If triangle have been legalized no need to check the other edges since
                            // the recursive legalization will handles those so we can end here.
                            return true;
                        }
                    }
                }
                return false;
            }

            /**
             * <b>Requirement</b>:<br>
             * 1. a,b and c form a triangle.<br>
             * 2. a and d is know to be on opposite side of bc<br>
             * <pre>
             *                a
             *                +
             *               / \
             *              /   \
             *            b/     \c
             *            +-------+
             *           /    d    \
             *          /           \
             * </pre>
             * <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by
             *  a,b and c<br>
             *  d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br>
             *  This preknowledge gives us a way to optimize the incircle test
             * @param pa - triangle point, opposite d
             * @param pb - triangle point
             * @param pc - triangle point
             * @param pd - point opposite a
             * @return {boolean} true if d is inside circle, false if on circle edge
             */
            function inCircle(pa, pb, pc, pd) {
                var adx = pa.x - pd.x;
                var ady = pa.y - pd.y;
                var bdx = pb.x - pd.x;
                var bdy = pb.y - pd.y;

                var adxbdy = adx * bdy;
                var bdxady = bdx * ady;
                var oabd = adxbdy - bdxady;
                if (oabd <= 0) {
                    return false;
                }

                var cdx = pc.x - pd.x;
                var cdy = pc.y - pd.y;

                var cdxady = cdx * ady;
                var adxcdy = adx * cdy;
                var ocad = cdxady - adxcdy;
                if (ocad <= 0) {
                    return false;
                }

                var bdxcdy = bdx * cdy;
                var cdxbdy = cdx * bdy;

                var alift = adx * adx + ady * ady;
                var blift = bdx * bdx + bdy * bdy;
                var clift = cdx * cdx + cdy * cdy;

                var det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
                return det > 0;
            }

            /**
             * Rotates a triangle pair one vertex CW
             *<pre>
             *       n2                    n2
             *  P +-----+             P +-----+
             *    | t  /|               |\  t |
             *    |   / |               | \   |
             *  n1|  /  |n3           n1|  \  |n3
             *    | /   |    after CW   |   \ |
             *    |/ oT |               | oT \|
             *    +-----+ oP            +-----+
             *       n4                    n4
             * </pre>
             */
            function rotateTrianglePair(t, p, ot, op) {
                var n1, n2, n3, n4;
                n1 = t.neighborCCW(p);
                n2 = t.neighborCW(p);
                n3 = ot.neighborCCW(op);
                n4 = ot.neighborCW(op);

                var ce1, ce2, ce3, ce4;
                ce1 = t.getConstrainedEdgeCCW(p);
                ce2 = t.getConstrainedEdgeCW(p);
                ce3 = ot.getConstrainedEdgeCCW(op);
                ce4 = ot.getConstrainedEdgeCW(op);

                var de1, de2, de3, de4;
                de1 = t.getDelaunayEdgeCCW(p);
                de2 = t.getDelaunayEdgeCW(p);
                de3 = ot.getDelaunayEdgeCCW(op);
                de4 = ot.getDelaunayEdgeCW(op);

                t.legalize(p, op);
                ot.legalize(op, p);

                // Remap delaunay_edge
                ot.setDelaunayEdgeCCW(p, de1);
                t.setDelaunayEdgeCW(p, de2);
                t.setDelaunayEdgeCCW(op, de3);
                ot.setDelaunayEdgeCW(op, de4);

                // Remap constrained_edge
                ot.setConstrainedEdgeCCW(p, ce1);
                t.setConstrainedEdgeCW(p, ce2);
                t.setConstrainedEdgeCCW(op, ce3);
                ot.setConstrainedEdgeCW(op, ce4);

                // Remap neighbors
                // XXX: might optimize the markNeighbor by keeping track of
                //      what side should be assigned to what neighbor after the
                //      rotation. Now mark neighbor does lots of testing to find
                //      the right side.
                t.clearNeighbors();
                ot.clearNeighbors();
                if (n1) {
                    ot.markNeighbor(n1);
                }
                if (n2) {
                    t.markNeighbor(n2);
                }
                if (n3) {
                    t.markNeighbor(n3);
                }
                if (n4) {
                    ot.markNeighbor(n4);
                }
                t.markNeighbor(ot);
            }

            /**
             * Fills a basin that has formed on the Advancing Front to the right
             * of given node.<br>
             * First we decide a left,bottom and right node that forms the
             * boundaries of the basin. Then we do a reqursive fill.
             *
             * @param {!SweepContext} tcx - SweepContext object
             * @param node - starting node, this or next node will be left node
             */
            function fillBasin(tcx, node) {
                if (orient2d(node.point, node.next.point, node.next.next.point) === Orientation.CCW) {
                    tcx.basin.left_node = node.next.next;
                } else {
                    tcx.basin.left_node = node.next;
                }

                // Find the bottom and right node
                tcx.basin.bottom_node = tcx.basin.left_node;
                while (tcx.basin.bottom_node.next && tcx.basin.bottom_node.point.y >= tcx.basin.bottom_node.next.point.y) {
                    tcx.basin.bottom_node = tcx.basin.bottom_node.next;
                }
                if (tcx.basin.bottom_node === tcx.basin.left_node) {
                    // No valid basin
                    return;
                }

                tcx.basin.right_node = tcx.basin.bottom_node;
                while (tcx.basin.right_node.next && tcx.basin.right_node.point.y < tcx.basin.right_node.next.point.y) {
                    tcx.basin.right_node = tcx.basin.right_node.next;
                }
                if (tcx.basin.right_node === tcx.basin.bottom_node) {
                    // No valid basins
                    return;
                }

                tcx.basin.width = tcx.basin.right_node.point.x - tcx.basin.left_node.point.x;
                tcx.basin.left_highest = tcx.basin.left_node.point.y > tcx.basin.right_node.point.y;

                fillBasinReq(tcx, tcx.basin.bottom_node);
            }

            /**
             * Recursive algorithm to fill a Basin with triangles
             *
             * @param {!SweepContext} tcx - SweepContext object
             * @param node - bottom_node
             */
            function fillBasinReq(tcx, node) {
                // if shallow stop filling
                if (isShallow(tcx, node)) {
                    return;
                }

                fill(tcx, node);

                var o;
                if (node.prev === tcx.basin.left_node && node.next === tcx.basin.right_node) {
                    return;
                } else if (node.prev === tcx.basin.left_node) {
                    o = orient2d(node.point, node.next.point, node.next.next.point);
                    if (o === Orientation.CW) {
                        return;
                    }
                    node = node.next;
                } else if (node.next === tcx.basin.right_node) {
                    o = orient2d(node.point, node.prev.point, node.prev.prev.point);
                    if (o === Orientation.CCW) {
                        return;
                    }
                    node = node.prev;
                } else {
                    // Continue with the neighbor node with lowest Y value
                    if (node.prev.point.y < node.next.point.y) {
                        node = node.prev;
                    } else {
                        node = node.next;
                    }
                }

                fillBasinReq(tcx, node);
            }

            function isShallow(tcx, node) {
                var height;
                if (tcx.basin.left_highest) {
                    height = tcx.basin.left_node.point.y - node.point.y;
                } else {
                    height = tcx.basin.right_node.point.y - node.point.y;
                }

                // if shallow stop filling
                if (tcx.basin.width > height) {
                    return true;
                }
                return false;
            }

            function fillEdgeEvent(tcx, edge, node) {
                if (tcx.edge_event.right) {
                    fillRightAboveEdgeEvent(tcx, edge, node);
                } else {
                    fillLeftAboveEdgeEvent(tcx, edge, node);
                }
            }

            function fillRightAboveEdgeEvent(tcx, edge, node) {
                while (node.next.point.x < edge.p.x) {
                    // Check if next node is below the edge
                    if (orient2d(edge.q, node.next.point, edge.p) === Orientation.CCW) {
                        fillRightBelowEdgeEvent(tcx, edge, node);
                    } else {
                        node = node.next;
                    }
                }
            }

            function fillRightBelowEdgeEvent(tcx, edge, node) {
                if (node.point.x < edge.p.x) {
                    if (orient2d(node.point, node.next.point, node.next.next.point) === Orientation.CCW) {
                        // Concave
                        fillRightConcaveEdgeEvent(tcx, edge, node);
                    } else {
                        // Convex
                        fillRightConvexEdgeEvent(tcx, edge, node);
                        // Retry this one
                        fillRightBelowEdgeEvent(tcx, edge, node);
                    }
                }
            }

            function fillRightConcaveEdgeEvent(tcx, edge, node) {
                fill(tcx, node.next);
                if (node.next.point !== edge.p) {
                    // Next above or below edge?
                    if (orient2d(edge.q, node.next.point, edge.p) === Orientation.CCW) {
                        // Below
                        if (orient2d(node.point, node.next.point, node.next.next.point) === Orientation.CCW) {
                            // Next is concave
                            fillRightConcaveEdgeEvent(tcx, edge, node);
                        } else {
                            // Next is convex
                            /* jshint noempty:false */
                        }
                    }
                }
            }

            function fillRightConvexEdgeEvent(tcx, edge, node) {
                // Next concave or convex?
                if (orient2d(node.next.point, node.next.next.point, node.next.next.next.point) === Orientation.CCW) {
                    // Concave
                    fillRightConcaveEdgeEvent(tcx, edge, node.next);
                } else {
                    // Convex
                    // Next above or below edge?
                    if (orient2d(edge.q, node.next.next.point, edge.p) === Orientation.CCW) {
                        // Below
                        fillRightConvexEdgeEvent(tcx, edge, node.next);
                    } else {
                        // Above
                        /* jshint noempty:false */
                    }
                }
            }

            function fillLeftAboveEdgeEvent(tcx, edge, node) {
                while (node.prev.point.x > edge.p.x) {
                    // Check if next node is below the edge
                    if (orient2d(edge.q, node.prev.point, edge.p) === Orientation.CW) {
                        fillLeftBelowEdgeEvent(tcx, edge, node);
                    } else {
                        node = node.prev;
                    }
                }
            }

            function fillLeftBelowEdgeEvent(tcx, edge, node) {
                if (node.point.x > edge.p.x) {
                    if (orient2d(node.point, node.prev.point, node.prev.prev.point) === Orientation.CW) {
                        // Concave
                        fillLeftConcaveEdgeEvent(tcx, edge, node);
                    } else {
                        // Convex
                        fillLeftConvexEdgeEvent(tcx, edge, node);
                        // Retry this one
                        fillLeftBelowEdgeEvent(tcx, edge, node);
                    }
                }
            }

            function fillLeftConvexEdgeEvent(tcx, edge, node) {
                // Next concave or convex?
                if (orient2d(node.prev.point, node.prev.prev.point, node.prev.prev.prev.point) === Orientation.CW) {
                    // Concave
                    fillLeftConcaveEdgeEvent(tcx, edge, node.prev);
                } else {
                    // Convex
                    // Next above or below edge?
                    if (orient2d(edge.q, node.prev.prev.point, edge.p) === Orientation.CW) {
                        // Below
                        fillLeftConvexEdgeEvent(tcx, edge, node.prev);
                    } else {
                        // Above
                        /* jshint noempty:false */
                    }
                }
            }

            function fillLeftConcaveEdgeEvent(tcx, edge, node) {
                fill(tcx, node.prev);
                if (node.prev.point !== edge.p) {
                    // Next above or below edge?
                    if (orient2d(edge.q, node.prev.point, edge.p) === Orientation.CW) {
                        // Below
                        if (orient2d(node.point, node.prev.point, node.prev.prev.point) === Orientation.CW) {
                            // Next is concave
                            fillLeftConcaveEdgeEvent(tcx, edge, node);
                        } else {
                            // Next is convex
                            /* jshint noempty:false */
                        }
                    }
                }
            }

            function flipEdgeEvent(tcx, ep, eq, t, p) {
                var ot = t.neighborAcross(p);
                assert(ot, "FLIP failed due to missing triangle!");

                var op = ot.oppositePoint(t, p);

                // Additional check from Java version (see issue #88)
                if (t.getConstrainedEdgeAcross(p)) {
                    var index = t.index(p);
                    throw new PointError("poly2tri Intersecting Constraints",
                        [p, op, t.getPoint((index + 1) % 3), t.getPoint((index + 2) % 3)]);
                }

                if (inScanArea(p, t.pointCCW(p), t.pointCW(p), op)) {
                    // Lets rotate shared edge one vertex CW
                    rotateTrianglePair(t, p, ot, op);
                    tcx.mapTriangleToNodes(t);
                    tcx.mapTriangleToNodes(ot);

                    // XXX: in the original C++ code for the next 2 lines, we are
                    // comparing point values (and not pointers). In this JavaScript
                    // code, we are comparing point references (pointers). This works
                    // because we can't have 2 different points with the same values.
                    // But to be really equivalent, we should use "Point.equals" here.
                    if (p === eq && op === ep) {
                        if (eq === tcx.edge_event.constrained_edge.q && ep === tcx.edge_event.constrained_edge.p) {
                            t.markConstrainedEdgeByPoints(ep, eq);
                            ot.markConstrainedEdgeByPoints(ep, eq);
                            legalize(tcx, t);
                            legalize(tcx, ot);
                        } else {
                            // XXX: I think one of the triangles should be legalized here?
                            /* jshint noempty:false */
                        }
                    } else {
                        var o = orient2d(eq, op, ep);
                        t = nextFlipTriangle(tcx, o, t, ot, p, op);
                        flipEdgeEvent(tcx, ep, eq, t, p);
                    }
                } else {
                    var newP = nextFlipPoint(ep, eq, ot, op);
                    flipScanEdgeEvent(tcx, ep, eq, t, ot, newP);
                    edgeEventByPoints(tcx, ep, eq, t, p);
                }
            }

            /**
             * After a flip we have two triangles and know that only one will still be
             * intersecting the edge. So decide which to contiune with and legalize the other
             *
             * @param {!SweepContext} tcx - SweepContext object
             * @param o - should be the result of an orient2d( eq, op, ep )
             * @param t - triangle 1
             * @param ot - triangle 2
             * @param p - a point shared by both triangles
             * @param op - another point shared by both triangles
             * @return returns the triangle still intersecting the edge
             */
            function nextFlipTriangle(tcx, o, t, ot, p, op) {
                var edge_index;
                if (o === Orientation.CCW) {
                    // ot is not crossing edge after flip
                    edge_index = ot.edgeIndex(p, op);
                    ot.delaunay_edge[edge_index] = true;
                    legalize(tcx, ot);
                    ot.clearDelaunayEdges();
                    return t;
                }

                // t is not crossing edge after flip
                edge_index = t.edgeIndex(p, op);

                t.delaunay_edge[edge_index] = true;
                legalize(tcx, t);
                t.clearDelaunayEdges();
                return ot;
            }

            /**
             * When we need to traverse from one triangle to the next we need
             * the point in current triangle that is the opposite point to the next
             * triangle.
             */
            function nextFlipPoint(ep, eq, ot, op) {
                var o2d = orient2d(eq, op, ep);
                if (o2d === Orientation.CW) {
                    // Right
                    return ot.pointCCW(op);
                } else if (o2d === Orientation.CCW) {
                    // Left
                    return ot.pointCW(op);
                } else {
                    throw new PointError("poly2tri [Unsupported] nextFlipPoint: opposing point on constrained edge!", [eq, op, ep]);
                }
            }

            /**
             * Scan part of the FlipScan algorithm<br>
             * When a triangle pair isn't flippable we will scan for the next
             * point that is inside the flip triangle scan area. When found
             * we generate a new flipEdgeEvent
             *
             * @param {!SweepContext} tcx - SweepContext object
             * @param ep - last point on the edge we are traversing
             * @param eq - first point on the edge we are traversing
             * @param {!Triangle} flip_triangle - the current triangle sharing the point eq with edge
             * @param t
             * @param p
             */
            function flipScanEdgeEvent(tcx, ep, eq, flip_triangle, t, p) {
                var ot = t.neighborAcross(p);
                assert(ot, "FLIP failed due to missing triangle");

                var op = ot.oppositePoint(t, p);

                if (inScanArea(eq, flip_triangle.pointCCW(eq), flip_triangle.pointCW(eq), op)) {
                    // flip with new edge op.eq
                    flipEdgeEvent(tcx, eq, op, ot, op);
                } else {
                    var newP = nextFlipPoint(ep, eq, ot, op);
                    flipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP);
                }
            }


            // ----------------------------------------------------------------------Exports

            exports.triangulate = triangulate;

        }, { "./advancingfront": 2, "./assert": 3, "./pointerror": 5, "./triangle": 9, "./utils": 10 }], 8: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            /* jshint maxcomplexity:6 */

            "use strict";


            /*
             * Note
             * ====
             * the structure of this JavaScript version of poly2tri intentionally follows
             * as closely as possible the structure of the reference C++ version, to make it
             * easier to keep the 2 versions in sync.
             */

            var PointError = require('./pointerror');
            var Point = require('./point');
            var Triangle = require('./triangle');
            var sweep = require('./sweep');
            var AdvancingFront = require('./advancingfront');
            var Node = AdvancingFront.Node;


            // ------------------------------------------------------------------------utils

            /**
             * Initial triangle factor, seed triangle will extend 30% of
             * PointSet width to both left and right.
             * @private
             * @const
             */
            var kAlpha = 0.3;


            // -------------------------------------------------------------------------Edge
            /**
             * Represents a simple polygon's edge
             * @constructor
             * @struct
             * @private
             * @param {Point} p1
             * @param {Point} p2
             * @throw {PointError} if p1 is same as p2
             */
            var Edge = function (p1, p2) {
                this.p = p1;
                this.q = p2;

                if (p1.y > p2.y) {
                    this.q = p1;
                    this.p = p2;
                } else if (p1.y === p2.y) {
                    if (p1.x > p2.x) {
                        this.q = p1;
                        this.p = p2;
                    } else if (p1.x === p2.x) {
                        throw new PointError('poly2tri Invalid Edge constructor: repeated points!', [p1]);
                    }
                }

                if (!this.q._p2t_edge_list) {
                    this.q._p2t_edge_list = [];
                }
                this.q._p2t_edge_list.push(this);
            };


            // ------------------------------------------------------------------------Basin
            /**
             * @constructor
             * @struct
             * @private
             */
            var Basin = function () {
                /** @type {Node} */
                this.left_node = null;
                /** @type {Node} */
                this.bottom_node = null;
                /** @type {Node} */
                this.right_node = null;
                /** @type {number} */
                this.width = 0.0;
                /** @type {boolean} */
                this.left_highest = false;
            };

            Basin.prototype.clear = function () {
                this.left_node = null;
                this.bottom_node = null;
                this.right_node = null;
                this.width = 0.0;
                this.left_highest = false;
            };

            // --------------------------------------------------------------------EdgeEvent
            /**
             * @constructor
             * @struct
             * @private
             */
            var EdgeEvent = function () {
                /** @type {Edge} */
                this.constrained_edge = null;
                /** @type {boolean} */
                this.right = false;
            };

            // ----------------------------------------------------SweepContext (public API)
            /**
             * SweepContext constructor option
             * @typedef {Object} SweepContextOptions
             * @property {boolean=} cloneArrays - if <code>true</code>, do a shallow copy of the Array parameters
             *                  (contour, holes). Points inside arrays are never copied.
             *                  Default is <code>false</code> : keep a reference to the array arguments,
             *                  who will be modified in place.
             */
            /**
             * Constructor for the triangulation context.
             * It accepts a simple polyline (with non repeating points),
             * which defines the constrained edges.
             *
             * @example
             *          var contour = [
             *              new poly2tri.Point(100, 100),
             *              new poly2tri.Point(100, 300),
             *              new poly2tri.Point(300, 300),
             *              new poly2tri.Point(300, 100)
             *          ];
             *          var swctx = new poly2tri.SweepContext(contour, {cloneArrays: true});
             * @example
             *          var contour = [{x:100, y:100}, {x:100, y:300}, {x:300, y:300}, {x:300, y:100}];
             *          var swctx = new poly2tri.SweepContext(contour, {cloneArrays: true});
             * @constructor
             * @public
             * @struct
             * @param {Array.<XY>} contour - array of point objects. The points can be either {@linkcode Point} instances,
             *          or any "Point like" custom class with <code>{x, y}</code> attributes.
             * @param {SweepContextOptions=} options - constructor options
             */
            var SweepContext = function (contour, options) {
                options = options || {};
                this.triangles_ = [];
                this.map_ = [];
                this.points_ = (options.cloneArrays ? contour.slice(0) : contour);
                this.edge_list = [];

                // Bounding box of all points. Computed at the start of the triangulation,
                // it is stored in case it is needed by the caller.
                this.pmin_ = this.pmax_ = null;

                /**
                 * Advancing front
                 * @private
                 * @type {AdvancingFront}
                 */
                this.front_ = null;

                /**
                 * head point used with advancing front
                 * @private
                 * @type {Point}
                 */
                this.head_ = null;

                /**
                 * tail point used with advancing front
                 * @private
                 * @type {Point}
                 */
                this.tail_ = null;

                /**
                 * @private
                 * @type {Node}
                 */
                this.af_head_ = null;
                /**
                 * @private
                 * @type {Node}
                 */
                this.af_middle_ = null;
                /**
                 * @private
                 * @type {Node}
                 */
                this.af_tail_ = null;

                this.basin = new Basin();
                this.edge_event = new EdgeEvent();

                this.initEdges(this.points_);
            };


            /**
             * Add a hole to the constraints
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      var hole = [
             *          new poly2tri.Point(200, 200),
             *          new poly2tri.Point(200, 250),
             *          new poly2tri.Point(250, 250)
             *      ];
             *      swctx.addHole(hole);
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.addHole([{x:200, y:200}, {x:200, y:250}, {x:250, y:250}]);
             * @public
             * @param {Array.<XY>} polyline - array of "Point like" objects with {x,y}
             */
            SweepContext.prototype.addHole = function (polyline) {
                this.initEdges(polyline);
                var i, len = polyline.length;
                for (i = 0; i < len; i++) {
                    this.points_.push(polyline[i]);
                }
                return this; // for chaining
            };

            /**
             * For backward compatibility
             * @function
             * @deprecated use {@linkcode SweepContext#addHole} instead
             */
            SweepContext.prototype.AddHole = SweepContext.prototype.addHole;


            /**
             * Add several holes to the constraints
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      var holes = [
             *          [ new poly2tri.Point(200, 200), new poly2tri.Point(200, 250), new poly2tri.Point(250, 250) ],
             *          [ new poly2tri.Point(300, 300), new poly2tri.Point(300, 350), new poly2tri.Point(350, 350) ]
             *      ];
             *      swctx.addHoles(holes);
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      var holes = [
             *          [{x:200, y:200}, {x:200, y:250}, {x:250, y:250}],
             *          [{x:300, y:300}, {x:300, y:350}, {x:350, y:350}]
             *      ];
             *      swctx.addHoles(holes);
             * @public
             * @param {Array.<Array.<XY>>} holes - array of array of "Point like" objects with {x,y}
             */
            // Method added in the JavaScript version (was not present in the c++ version)
            SweepContext.prototype.addHoles = function (holes) {
                var i, len = holes.length;
                for (i = 0; i < len; i++) {
                    this.initEdges(holes[i]);
                }
                this.points_ = this.points_.concat.apply(this.points_, holes);
                return this; // for chaining
            };


            /**
             * Add a Steiner point to the constraints
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      var point = new poly2tri.Point(150, 150);
             *      swctx.addPoint(point);
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.addPoint({x:150, y:150});
             * @public
             * @param {XY} point - any "Point like" object with {x,y}
             */
            SweepContext.prototype.addPoint = function (point) {
                this.points_.push(point);
                return this; // for chaining
            };

            /**
             * For backward compatibility
             * @function
             * @deprecated use {@linkcode SweepContext#addPoint} instead
             */
            SweepContext.prototype.AddPoint = SweepContext.prototype.addPoint;


            /**
             * Add several Steiner points to the constraints
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      var points = [
             *          new poly2tri.Point(150, 150),
             *          new poly2tri.Point(200, 250),
             *          new poly2tri.Point(250, 250)
             *      ];
             *      swctx.addPoints(points);
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.addPoints([{x:150, y:150}, {x:200, y:250}, {x:250, y:250}]);
             * @public
             * @param {Array.<XY>} points - array of "Point like" object with {x,y}
             */
            // Method added in the JavaScript version (was not present in the c++ version)
            SweepContext.prototype.addPoints = function (points) {
                this.points_ = this.points_.concat(points);
                return this; // for chaining
            };


            /**
             * Triangulate the polygon with holes and Steiner points.
             * Do this AFTER you've added the polyline, holes, and Steiner points
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.triangulate();
             *      var triangles = swctx.getTriangles();
             * @public
             */
            // Shortcut method for sweep.triangulate(SweepContext).
            // Method added in the JavaScript version (was not present in the c++ version)
            SweepContext.prototype.triangulate = function () {
                sweep.triangulate(this);
                return this; // for chaining
            };


            /**
             * Get the bounding box of the provided constraints (contour, holes and
             * Steinter points). Warning : these values are not available if the triangulation
             * has not been done yet.
             * @public
             * @returns {{min:Point,max:Point}} object with 'min' and 'max' Point
             */
            // Method added in the JavaScript version (was not present in the c++ version)
            SweepContext.prototype.getBoundingBox = function () {
                return { min: this.pmin_, max: this.pmax_ };
            };

            /**
             * Get result of triangulation.
             * The output triangles have vertices which are references
             * to the initial input points (not copies): any custom fields in the
             * initial points can be retrieved in the output triangles.
             * @example
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.triangulate();
             *      var triangles = swctx.getTriangles();
             * @example
             *      var contour = [{x:100, y:100, id:1}, {x:100, y:300, id:2}, {x:300, y:300, id:3}];
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.triangulate();
             *      var triangles = swctx.getTriangles();
             *      typeof triangles[0].getPoint(0).id
             *      // → "number"
             * @public
             * @returns {array<Triangle>}   array of triangles
             */
            SweepContext.prototype.getTriangles = function () {
                return this.triangles_;
            };

            /**
             * For backward compatibility
             * @function
             * @deprecated use {@linkcode SweepContext#getTriangles} instead
             */
            SweepContext.prototype.GetTriangles = SweepContext.prototype.getTriangles;


            // ---------------------------------------------------SweepContext (private API)

            /** @private */
            SweepContext.prototype.front = function () {
                return this.front_;
            };

            /** @private */
            SweepContext.prototype.pointCount = function () {
                return this.points_.length;
            };

            /** @private */
            SweepContext.prototype.head = function () {
                return this.head_;
            };

            /** @private */
            SweepContext.prototype.setHead = function (p1) {
                this.head_ = p1;
            };

            /** @private */
            SweepContext.prototype.tail = function () {
                return this.tail_;
            };

            /** @private */
            SweepContext.prototype.setTail = function (p1) {
                this.tail_ = p1;
            };

            /** @private */
            SweepContext.prototype.getMap = function () {
                return this.map_;
            };

            /** @private */
            SweepContext.prototype.initTriangulation = function () {
                var xmax = this.points_[0].x;
                var xmin = this.points_[0].x;
                var ymax = this.points_[0].y;
                var ymin = this.points_[0].y;

                // Calculate bounds
                var i, len = this.points_.length;
                for (i = 1; i < len; i++) {
                    var p = this.points_[i];
                    /* jshint expr:true */
                    (p.x > xmax) && (xmax = p.x);
                    (p.x < xmin) && (xmin = p.x);
                    (p.y > ymax) && (ymax = p.y);
                    (p.y < ymin) && (ymin = p.y);
                }
                this.pmin_ = new Point(xmin, ymin);
                this.pmax_ = new Point(xmax, ymax);

                var dx = kAlpha * (xmax - xmin);
                var dy = kAlpha * (ymax - ymin);
                this.head_ = new Point(xmax + dx, ymin - dy);
                this.tail_ = new Point(xmin - dx, ymin - dy);

                // Sort points along y-axis
                this.points_.sort(Point.compare);
            };

            /** @private */
            SweepContext.prototype.initEdges = function (polyline) {
                var i, len = polyline.length;
                for (i = 0; i < len; ++i) {
                    this.edge_list.push(new Edge(polyline[i], polyline[(i + 1) % len]));
                }
            };

            /** @private */
            SweepContext.prototype.getPoint = function (index) {
                return this.points_[index];
            };

            /** @private */
            SweepContext.prototype.addToMap = function (triangle) {
                this.map_.push(triangle);
            };

            /** @private */
            SweepContext.prototype.locateNode = function (point) {
                return this.front_.locateNode(point.x);
            };

            /** @private */
            SweepContext.prototype.createAdvancingFront = function () {
                var head;
                var middle;
                var tail;
                // Initial triangle
                var triangle = new Triangle(this.points_[0], this.tail_, this.head_);

                this.map_.push(triangle);

                head = new Node(triangle.getPoint(1), triangle);
                middle = new Node(triangle.getPoint(0), triangle);
                tail = new Node(triangle.getPoint(2));

                this.front_ = new AdvancingFront(head, tail);

                head.next = middle;
                middle.next = tail;
                middle.prev = head;
                tail.prev = middle;
            };

            /** @private */
            SweepContext.prototype.removeNode = function (node) {
                // do nothing
                /* jshint unused:false */
            };

            /** @private */
            SweepContext.prototype.mapTriangleToNodes = function (t) {
                for (var i = 0; i < 3; ++i) {
                    if (!t.getNeighbor(i)) {
                        var n = this.front_.locatePoint(t.pointCW(t.getPoint(i)));
                        if (n) {
                            n.triangle = t;
                        }
                    }
                }
            };

            /** @private */
            SweepContext.prototype.removeFromMap = function (triangle) {
                var i, map = this.map_, len = map.length;
                for (i = 0; i < len; i++) {
                    if (map[i] === triangle) {
                        map.splice(i, 1);
                        break;
                    }
                }
            };

            /**
             * Do a depth first traversal to collect triangles
             * @private
             * @param {Triangle} triangle start
             */
            SweepContext.prototype.meshClean = function (triangle) {
                // New implementation avoids recursive calls and use a loop instead.
                // Cf. issues # 57, 65 and 69.
                var triangles = [triangle], t, i;
                /* jshint boss:true */
                while (t = triangles.pop()) {
                    if (!t.isInterior()) {
                        t.setInterior(true);
                        this.triangles_.push(t);
                        for (i = 0; i < 3; i++) {
                            if (!t.constrained_edge[i]) {
                                triangles.push(t.getNeighbor(i));
                            }
                        }
                    }
                }
            };

            // ----------------------------------------------------------------------Exports

            module.exports = SweepContext;

        }, { "./advancingfront": 2, "./point": 4, "./pointerror": 5, "./sweep": 7, "./triangle": 9 }], 9: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            /* jshint maxcomplexity:10 */

            "use strict";


            /*
             * Note
             * ====
             * the structure of this JavaScript version of poly2tri intentionally follows
             * as closely as possible the structure of the reference C++ version, to make it
             * easier to keep the 2 versions in sync.
             */

            var xy = require("./xy");


            // ---------------------------------------------------------------------Triangle
            /**
             * Triangle class.<br>
             * Triangle-based data structures are known to have better performance than
             * quad-edge structures.
             * See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and
             * Delaunay Triangulator", "Triangulations in CGAL"
             *
             * @constructor
             * @struct
             * @param {!XY} pa  point object with {x,y}
             * @param {!XY} pb  point object with {x,y}
             * @param {!XY} pc  point object with {x,y}
             */
            var Triangle = function (a, b, c) {
                /**
                 * Triangle points
                 * @private
                 * @type {Array.<XY>}
                 */
                this.points_ = [a, b, c];

                /**
                 * Neighbor list
                 * @private
                 * @type {Array.<Triangle>}
                 */
                this.neighbors_ = [null, null, null];

                /**
                 * Has this triangle been marked as an interior triangle?
                 * @private
                 * @type {boolean}
                 */
                this.interior_ = false;

                /**
                 * Flags to determine if an edge is a Constrained edge
                 * @private
                 * @type {Array.<boolean>}
                 */
                this.constrained_edge = [false, false, false];

                /**
                 * Flags to determine if an edge is a Delauney edge
                 * @private
                 * @type {Array.<boolean>}
                 */
                this.delaunay_edge = [false, false, false];
            };

            var p2s = xy.toString;
            /**
             * For pretty printing ex. <code>"[(5;42)(10;20)(21;30)]"</code>.
             * @public
             * @return {string}
             */
            Triangle.prototype.toString = function () {
                return ("[" + p2s(this.points_[0]) + p2s(this.points_[1]) + p2s(this.points_[2]) + "]");
            };

            /**
             * Get one vertice of the triangle.
             * The output triangles of a triangulation have vertices which are references
             * to the initial input points (not copies): any custom fields in the
             * initial points can be retrieved in the output triangles.
             * @example
             *      var contour = [{x:100, y:100, id:1}, {x:100, y:300, id:2}, {x:300, y:300, id:3}];
             *      var swctx = new poly2tri.SweepContext(contour);
             *      swctx.triangulate();
             *      var triangles = swctx.getTriangles();
             *      typeof triangles[0].getPoint(0).id
             *      // → "number"
             * @param {number} index - vertice index: 0, 1 or 2
             * @public
             * @returns {XY}
             */
            Triangle.prototype.getPoint = function (index) {
                return this.points_[index];
            };

            /**
             * For backward compatibility
             * @function
             * @deprecated use {@linkcode Triangle#getPoint} instead
             */
            Triangle.prototype.GetPoint = Triangle.prototype.getPoint;

            /**
             * Get all 3 vertices of the triangle as an array
             * @public
             * @return {Array.<XY>}
             */
            // Method added in the JavaScript version (was not present in the c++ version)
            Triangle.prototype.getPoints = function () {
                return this.points_;
            };

            /**
             * @private
             * @param {number} index
             * @returns {?Triangle}
             */
            Triangle.prototype.getNeighbor = function (index) {
                return this.neighbors_[index];
            };

            /**
             * Test if this Triangle contains the Point object given as parameter as one of its vertices.
             * Only point references are compared, not values.
             * @public
             * @param {XY} point - point object with {x,y}
             * @return {boolean} <code>True</code> if the Point object is of the Triangle's vertices,
             *         <code>false</code> otherwise.
             */
            Triangle.prototype.containsPoint = function (point) {
                var points = this.points_;
                // Here we are comparing point references, not values
                return (point === points[0] || point === points[1] || point === points[2]);
            };

            /**
             * Test if this Triangle contains the Edge object given as parameter as its
             * bounding edges. Only point references are compared, not values.
             * @private
             * @param {Edge} edge
             * @return {boolean} <code>True</code> if the Edge object is of the Triangle's bounding
             *         edges, <code>false</code> otherwise.
             */
            Triangle.prototype.containsEdge = function (edge) {
                return this.containsPoint(edge.p) && this.containsPoint(edge.q);
            };

            /**
             * Test if this Triangle contains the two Point objects given as parameters among its vertices.
             * Only point references are compared, not values.
             * @param {XY} p1 - point object with {x,y}
             * @param {XY} p2 - point object with {x,y}
             * @return {boolean}
             */
            Triangle.prototype.containsPoints = function (p1, p2) {
                return this.containsPoint(p1) && this.containsPoint(p2);
            };

            /**
             * Has this triangle been marked as an interior triangle?
             * @returns {boolean}
             */
            Triangle.prototype.isInterior = function () {
                return this.interior_;
            };

            /**
             * Mark this triangle as an interior triangle
             * @private
             * @param {boolean} interior
             * @returns {Triangle} this
             */
            Triangle.prototype.setInterior = function (interior) {
                this.interior_ = interior;
                return this;
            };

            /**
             * Update neighbor pointers.
             * @private
             * @param {XY} p1 - point object with {x,y}
             * @param {XY} p2 - point object with {x,y}
             * @param {Triangle} t Triangle object.
             * @throws {Error} if can't find objects
             */
            Triangle.prototype.markNeighborPointers = function (p1, p2, t) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if ((p1 === points[2] && p2 === points[1]) || (p1 === points[1] && p2 === points[2])) {
                    this.neighbors_[0] = t;
                } else if ((p1 === points[0] && p2 === points[2]) || (p1 === points[2] && p2 === points[0])) {
                    this.neighbors_[1] = t;
                } else if ((p1 === points[0] && p2 === points[1]) || (p1 === points[1] && p2 === points[0])) {
                    this.neighbors_[2] = t;
                } else {
                    throw new Error('poly2tri Invalid Triangle.markNeighborPointers() call');
                }
            };

            /**
             * Exhaustive search to update neighbor pointers
             * @private
             * @param {!Triangle} t
             */
            Triangle.prototype.markNeighbor = function (t) {
                var points = this.points_;
                if (t.containsPoints(points[1], points[2])) {
                    this.neighbors_[0] = t;
                    t.markNeighborPointers(points[1], points[2], this);
                } else if (t.containsPoints(points[0], points[2])) {
                    this.neighbors_[1] = t;
                    t.markNeighborPointers(points[0], points[2], this);
                } else if (t.containsPoints(points[0], points[1])) {
                    this.neighbors_[2] = t;
                    t.markNeighborPointers(points[0], points[1], this);
                }
            };


            Triangle.prototype.clearNeighbors = function () {
                this.neighbors_[0] = null;
                this.neighbors_[1] = null;
                this.neighbors_[2] = null;
            };

            Triangle.prototype.clearDelaunayEdges = function () {
                this.delaunay_edge[0] = false;
                this.delaunay_edge[1] = false;
                this.delaunay_edge[2] = false;
            };

            /**
             * Returns the point clockwise to the given point.
             * @private
             * @param {XY} p - point object with {x,y}
             */
            Triangle.prototype.pointCW = function (p) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if (p === points[0]) {
                    return points[2];
                } else if (p === points[1]) {
                    return points[0];
                } else if (p === points[2]) {
                    return points[1];
                } else {
                    return null;
                }
            };

            /**
             * Returns the point counter-clockwise to the given point.
             * @private
             * @param {XY} p - point object with {x,y}
             */
            Triangle.prototype.pointCCW = function (p) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if (p === points[0]) {
                    return points[1];
                } else if (p === points[1]) {
                    return points[2];
                } else if (p === points[2]) {
                    return points[0];
                } else {
                    return null;
                }
            };

            /**
             * Returns the neighbor clockwise to given point.
             * @private
             * @param {XY} p - point object with {x,y}
             */
            Triangle.prototype.neighborCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.neighbors_[1];
                } else if (p === this.points_[1]) {
                    return this.neighbors_[2];
                } else {
                    return this.neighbors_[0];
                }
            };

            /**
             * Returns the neighbor counter-clockwise to given point.
             * @private
             * @param {XY} p - point object with {x,y}
             */
            Triangle.prototype.neighborCCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.neighbors_[2];
                } else if (p === this.points_[1]) {
                    return this.neighbors_[0];
                } else {
                    return this.neighbors_[1];
                }
            };

            Triangle.prototype.getConstrainedEdgeCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.constrained_edge[1];
                } else if (p === this.points_[1]) {
                    return this.constrained_edge[2];
                } else {
                    return this.constrained_edge[0];
                }
            };

            Triangle.prototype.getConstrainedEdgeCCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.constrained_edge[2];
                } else if (p === this.points_[1]) {
                    return this.constrained_edge[0];
                } else {
                    return this.constrained_edge[1];
                }
            };

            // Additional check from Java version (see issue #88)
            Triangle.prototype.getConstrainedEdgeAcross = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.constrained_edge[0];
                } else if (p === this.points_[1]) {
                    return this.constrained_edge[1];
                } else {
                    return this.constrained_edge[2];
                }
            };

            Triangle.prototype.setConstrainedEdgeCW = function (p, ce) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    this.constrained_edge[1] = ce;
                } else if (p === this.points_[1]) {
                    this.constrained_edge[2] = ce;
                } else {
                    this.constrained_edge[0] = ce;
                }
            };

            Triangle.prototype.setConstrainedEdgeCCW = function (p, ce) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    this.constrained_edge[2] = ce;
                } else if (p === this.points_[1]) {
                    this.constrained_edge[0] = ce;
                } else {
                    this.constrained_edge[1] = ce;
                }
            };

            Triangle.prototype.getDelaunayEdgeCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.delaunay_edge[1];
                } else if (p === this.points_[1]) {
                    return this.delaunay_edge[2];
                } else {
                    return this.delaunay_edge[0];
                }
            };

            Triangle.prototype.getDelaunayEdgeCCW = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.delaunay_edge[2];
                } else if (p === this.points_[1]) {
                    return this.delaunay_edge[0];
                } else {
                    return this.delaunay_edge[1];
                }
            };

            Triangle.prototype.setDelaunayEdgeCW = function (p, e) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    this.delaunay_edge[1] = e;
                } else if (p === this.points_[1]) {
                    this.delaunay_edge[2] = e;
                } else {
                    this.delaunay_edge[0] = e;
                }
            };

            Triangle.prototype.setDelaunayEdgeCCW = function (p, e) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    this.delaunay_edge[2] = e;
                } else if (p === this.points_[1]) {
                    this.delaunay_edge[0] = e;
                } else {
                    this.delaunay_edge[1] = e;
                }
            };

            /**
             * The neighbor across to given point.
             * @private
             * @param {XY} p - point object with {x,y}
             * @returns {Triangle}
             */
            Triangle.prototype.neighborAcross = function (p) {
                // Here we are comparing point references, not values
                if (p === this.points_[0]) {
                    return this.neighbors_[0];
                } else if (p === this.points_[1]) {
                    return this.neighbors_[1];
                } else {
                    return this.neighbors_[2];
                }
            };

            /**
             * @private
             * @param {!Triangle} t Triangle object.
             * @param {XY} p - point object with {x,y}
             */
            Triangle.prototype.oppositePoint = function (t, p) {
                var cw = t.pointCW(p);
                return this.pointCW(cw);
            };

            /**
             * Legalize triangle by rotating clockwise around oPoint
             * @private
             * @param {XY} opoint - point object with {x,y}
             * @param {XY} npoint - point object with {x,y}
             * @throws {Error} if oPoint can not be found
             */
            Triangle.prototype.legalize = function (opoint, npoint) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if (opoint === points[0]) {
                    points[1] = points[0];
                    points[0] = points[2];
                    points[2] = npoint;
                } else if (opoint === points[1]) {
                    points[2] = points[1];
                    points[1] = points[0];
                    points[0] = npoint;
                } else if (opoint === points[2]) {
                    points[0] = points[2];
                    points[2] = points[1];
                    points[1] = npoint;
                } else {
                    throw new Error('poly2tri Invalid Triangle.legalize() call');
                }
            };

            /**
             * Returns the index of a point in the triangle.
             * The point *must* be a reference to one of the triangle's vertices.
             * @private
             * @param {XY} p - point object with {x,y}
             * @returns {number} index 0, 1 or 2
             * @throws {Error} if p can not be found
             */
            Triangle.prototype.index = function (p) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if (p === points[0]) {
                    return 0;
                } else if (p === points[1]) {
                    return 1;
                } else if (p === points[2]) {
                    return 2;
                } else {
                    throw new Error('poly2tri Invalid Triangle.index() call');
                }
            };

            /**
             * @private
             * @param {XY} p1 - point object with {x,y}
             * @param {XY} p2 - point object with {x,y}
             * @return {number} index 0, 1 or 2, or -1 if errror
             */
            Triangle.prototype.edgeIndex = function (p1, p2) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if (p1 === points[0]) {
                    if (p2 === points[1]) {
                        return 2;
                    } else if (p2 === points[2]) {
                        return 1;
                    }
                } else if (p1 === points[1]) {
                    if (p2 === points[2]) {
                        return 0;
                    } else if (p2 === points[0]) {
                        return 2;
                    }
                } else if (p1 === points[2]) {
                    if (p2 === points[0]) {
                        return 1;
                    } else if (p2 === points[1]) {
                        return 0;
                    }
                }
                return -1;
            };

            /**
             * Mark an edge of this triangle as constrained.
             * @private
             * @param {number} index - edge index
             */
            Triangle.prototype.markConstrainedEdgeByIndex = function (index) {
                this.constrained_edge[index] = true;
            };
            /**
             * Mark an edge of this triangle as constrained.
             * @private
             * @param {Edge} edge instance
             */
            Triangle.prototype.markConstrainedEdgeByEdge = function (edge) {
                this.markConstrainedEdgeByPoints(edge.p, edge.q);
            };
            /**
             * Mark an edge of this triangle as constrained.
             * This method takes two Point instances defining the edge of the triangle.
             * @private
             * @param {XY} p - point object with {x,y}
             * @param {XY} q - point object with {x,y}
             */
            Triangle.prototype.markConstrainedEdgeByPoints = function (p, q) {
                var points = this.points_;
                // Here we are comparing point references, not values
                if ((q === points[0] && p === points[1]) || (q === points[1] && p === points[0])) {
                    this.constrained_edge[2] = true;
                } else if ((q === points[0] && p === points[2]) || (q === points[2] && p === points[0])) {
                    this.constrained_edge[1] = true;
                } else if ((q === points[1] && p === points[2]) || (q === points[2] && p === points[1])) {
                    this.constrained_edge[0] = true;
                }
            };


            // ---------------------------------------------------------Exports (public API)

            module.exports = Triangle;

        }, { "./xy": 11 }], 10: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            "use strict";

            /**
             * Precision to detect repeated or collinear points
             * @private
             * @const {number}
             * @default
             */
            var EPSILON = 1e-12;
            exports.EPSILON = EPSILON;

            /**
             * @private
             * @enum {number}
             * @readonly
             */
            var Orientation = {
                "CW": 1,
                "CCW": -1,
                "COLLINEAR": 0
            };
            exports.Orientation = Orientation;


            /**
             * Formula to calculate signed area<br>
             * Positive if CCW<br>
             * Negative if CW<br>
             * 0 if collinear<br>
             * <pre>
             * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
             *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
             * </pre>
             *
             * @private
             * @param {!XY} pa  point object with {x,y}
             * @param {!XY} pb  point object with {x,y}
             * @param {!XY} pc  point object with {x,y}
             * @return {Orientation}
             */
            function orient2d(pa, pb, pc) {
                var detleft = (pa.x - pc.x) * (pb.y - pc.y);
                var detright = (pa.y - pc.y) * (pb.x - pc.x);
                var val = detleft - detright;
                if (val > -(EPSILON) && val < (EPSILON)) {
                    return Orientation.COLLINEAR;
                } else if (val > 0) {
                    return Orientation.CCW;
                } else {
                    return Orientation.CW;
                }
            }
            exports.orient2d = orient2d;


            /**
             *
             * @private
             * @param {!XY} pa  point object with {x,y}
             * @param {!XY} pb  point object with {x,y}
             * @param {!XY} pc  point object with {x,y}
             * @param {!XY} pd  point object with {x,y}
             * @return {boolean}
             */
            function inScanArea(pa, pb, pc, pd) {
                var oadb = (pa.x - pb.x) * (pd.y - pb.y) - (pd.x - pb.x) * (pa.y - pb.y);
                if (oadb >= -EPSILON) {
                    return false;
                }

                var oadc = (pa.x - pc.x) * (pd.y - pc.y) - (pd.x - pc.x) * (pa.y - pc.y);
                if (oadc <= EPSILON) {
                    return false;
                }
                return true;
            }
            exports.inScanArea = inScanArea;


            /**
             * Check if the angle between (pa,pb) and (pa,pc) is obtuse i.e. (angle > π/2 || angle < -π/2)
             *
             * @private
             * @param {!XY} pa  point object with {x,y}
             * @param {!XY} pb  point object with {x,y}
             * @param {!XY} pc  point object with {x,y}
             * @return {boolean} true if angle is obtuse
             */
            function isAngleObtuse(pa, pb, pc) {
                var ax = pb.x - pa.x;
                var ay = pb.y - pa.y;
                var bx = pc.x - pa.x;
                var by = pc.y - pa.y;
                return (ax * bx + ay * by) < 0;
            }
            exports.isAngleObtuse = isAngleObtuse;


        }, {}], 11: [function (require, module, exports) {
            /*
             * Poly2Tri Copyright (c) 2009-2014, Poly2Tri Contributors
             * http://code.google.com/p/poly2tri/
             *
             * poly2tri.js (JavaScript port) (c) 2009-2014, Poly2Tri Contributors
             * https://github.com/r3mi/poly2tri.js
             *
             * All rights reserved.
             *
             * Distributed under the 3-clause BSD License, see LICENSE.txt
             */

            "use strict";

            /**
             * The following functions operate on "Point" or any "Point like" object with {x,y},
             * as defined by the {@link XY} type
             * ([duck typing]{@link http://en.wikipedia.org/wiki/Duck_typing}).
             * @module
             * @private
             */

            /**
             * poly2tri.js supports using custom point class instead of {@linkcode Point}.
             * Any "Point like" object with <code>{x, y}</code> attributes is supported
             * to initialize the SweepContext polylines and points
             * ([duck typing]{@link http://en.wikipedia.org/wiki/Duck_typing}).
             *
             * poly2tri.js might add extra fields to the point objects when computing the
             * triangulation : they are prefixed with <code>_p2t_</code> to avoid collisions
             * with fields in the custom class.
             *
             * @example
             *      var contour = [{x:100, y:100}, {x:100, y:300}, {x:300, y:300}, {x:300, y:100}];
             *      var swctx = new poly2tri.SweepContext(contour);
             *
             * @typedef {Object} XY
             * @property {number} x - x coordinate
             * @property {number} y - y coordinate
             */


            /**
             * Point pretty printing : prints x and y coordinates.
             * @example
             *      xy.toStringBase({x:5, y:42})
             *      // → "(5;42)"
             * @protected
             * @param {!XY} p - point object with {x,y}
             * @returns {string} <code>"(x;y)"</code>
             */
            function toStringBase(p) {
                return ("(" + p.x + ";" + p.y + ")");
            }

            /**
             * Point pretty printing. Delegates to the point's custom "toString()" method if exists,
             * else simply prints x and y coordinates.
             * @example
             *      xy.toString({x:5, y:42})
             *      // → "(5;42)"
             * @example
             *      xy.toString({x:5,y:42,toString:function() {return this.x+":"+this.y;}})
             *      // → "5:42"
             * @param {!XY} p - point object with {x,y}
             * @returns {string} <code>"(x;y)"</code>
             */
            function toString(p) {
                // Try a custom toString first, and fallback to own implementation if none
                var s = p.toString();
                return (s === '[object Object]' ? toStringBase(p) : s);
            }


            /**
             * Compare two points component-wise. Ordered by y axis first, then x axis.
             * @param {!XY} a - point object with {x,y}
             * @param {!XY} b - point object with {x,y}
             * @return {number} <code>&lt; 0</code> if <code>a &lt; b</code>,
             *         <code>&gt; 0</code> if <code>a &gt; b</code>,
             *         <code>0</code> otherwise.
             */
            function compare(a, b) {
                if (a.y === b.y) {
                    return a.x - b.x;
                } else {
                    return a.y - b.y;
                }
            }

            /**
             * Test two Point objects for equality.
             * @param {!XY} a - point object with {x,y}
             * @param {!XY} b - point object with {x,y}
             * @return {boolean} <code>True</code> if <code>a == b</code>, <code>false</code> otherwise.
             */
            function equals(a, b) {
                return a.x === b.x && a.y === b.y;
            }


            module.exports = {
                toString: toString,
                toStringBase: toStringBase,
                compare: compare,
                equals: equals
            };

        }, {}]
    }, {}, [6])(6)
});
